package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constansts.WemediaConstants;
import com.heima.common.exception.CustomException;
import com.heima.feign.article.ArticleFeign;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dto.WmNewsDto;
import com.heima.model.wemedia.dto.WmNewsPageReqDto;
import com.heima.model.wemedia.dto.WmNewsUpAndDownDto;
import com.heima.model.wemedia.pojo.WmMaterial;
import com.heima.model.wemedia.pojo.WmNews;
import com.heima.model.wemedia.pojo.WmNewsMaterial;
import com.heima.wemedia.mapper.*;
import com.heima.wemedia.service.WmNewSVerfiyService;
import com.heima.wemedia.service.WmNewsService;
import com.heima.utils.common.UserThreadLocal;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.heima.common.constansts.WemediaConstants.WM_NEWS_MANY_IMAGE;

@Service
@Slf4j
@Transactional
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    private ArticleFeign articleFeign;

    @Autowired
    private WmNewSVerfiyService wmNewSVerfiyService;
    /**
     * 查询文章
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult<List<WmNews>> findAll(WmNewsPageReqDto dto) {
        //参数健壮性判断
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //检查参数
        dto.checkParam();
        //分页查询
        //从参数中获取查询页数和要查询条数
        Integer page = dto.getPage();
        Integer size = dto.getSize();
        //创建page对象
        IPage<WmNews> pageInfo = new Page<>(page, size);
        //创建LambdaQueryWrapper对象封装查询条件
        LambdaQueryWrapper<WmNews> queryWrapper = new LambdaQueryWrapper<>();
        //获取当前登录用户id
        Integer userId = UserThreadLocal.getUserId();
        if (userId == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //状态条件精确查询
        queryWrapper.eq(dto.getStatus() != null, WmNews::getStatus, dto.getStatus());
        //频道精确查询
        queryWrapper.eq(dto.getChannelId() != null, WmNews::getChannelId, dto.getChannelId());
        //时间范围查询
        queryWrapper.between(
                dto.getBeginPubdate() != null && dto.getEndPubdate() != null,
                WmNews::getPublishTime,
                dto.getBeginPubdate(),
                dto.getEndPubdate()
        );
        //关键字模糊查询
        queryWrapper.like(dto.getKeyword() != null, WmNews::getTitle, dto.getKeyword());
        //查询当前登录用户的文章
        queryWrapper.eq(WmNews::getUserId, userId);
        //发布时间倒序查询
        queryWrapper.orderByDesc(WmNews::getPublishTime);
        //调用page方法查询
        IPage<WmNews> newsIPage = this.page(pageInfo, queryWrapper);
        List<WmNews> records = newsIPage.getRecords();
        ResponseResult<List<WmNews>> response = new ResponseResult();
        response.setData(records);

        return response;
    }

    /**
     * 保存修改文章
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult submitNews(WmNewsDto dto) {
        //0.条件判断
        if (dto == null || dto.getContent() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //保存文章数据到WmNews表中
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(dto, wmNews);
        List<String> images = dto.getImages();
        //封面图片  list---> string
        if (images != null && images.size() > 0) {
            String image = StringUtils.join(images, ",");
            wmNews.setImages(image);
        }
        //补齐登录的其他属性
        wmNews.setUserId(UserThreadLocal.getUserId());
        wmNews.setCreatedTime(new Date());
        wmNews.setSubmitedTime(new Date());
        wmNews.setEnable((short) 1);

        //处理封面
        if (wmNews.getType() == -1) {
            wmNews.setType(null);
            //自动,封面图片从内容中获取
        }
        //保存或修改文章
        if (wmNews.getId() == null) {
            //id为空则执行保存操作
            this.save(wmNews);
        } else {
            //id不为空则为修改操作
            //先删除已关联素材关系
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId, wmNews.getId()));
            //修改文章
            this.updateById(wmNews);
        }

        //判断是否为草稿如果是则直接结束当前方法
        if (wmNews.getStatus().equals(WmNews.Status.NORMAL.getCode())){
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }
        //提取内容中的图片信息
        List<String> materials = ectractUrlInfo(dto.getContent());
        saveRelativeInfoForContent(materials, wmNews.getId());

        //不是草稿则保存文章内容图片与素材的关系
        saveRelativeInfoForCover(dto,wmNews,materials);

        //自动审核文章是否合法,远程调用文章微服务，保存APP端文章
        try {
            wmNewSVerfiyService.verfiy(wmNews);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        //响应结果
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 自媒体文章上下架功能
     * @param dto
     * @return
     */
    @Override
    public ResponseResult upOrDown(WmNewsUpAndDownDto dto) {
        //1.检查参数
        if(dto.getId() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //获取文章id
        Integer id = dto.getId();
        //根据id查询文章
        WmNews wmNews = this.getById(id);
        //文章不存在则返回错误信息
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //查看文章状态,如果不为9已发布,则不能下架
        Short status = wmNews.getStatus();
        if (!(status == WmNews.Status.PUBLISHED.getCode())){
            return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH);
        }
        //修改文章enable属性
        Short enable = dto.getEnable();
        wmNews.setEnable(enable);
        this.updateById(wmNews);
        //通过kafka发送消息
        Long articleId = wmNews.getArticleId();
        //
        kafkaTemplate.send("upOrDown", String.valueOf(articleId), String.valueOf(enable));
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;
    @Autowired
    private WmUserMapper wmUserMapper;
    @Autowired
    private WmChannelMapper wmChannelMapper;
    /**
     * 第一个功能：如果当前封面类型为自动，则设置封面类型的数据
     * 匹配规则：
     * 1，如果内容图片大于等于1，小于3  单图  type 1
     * 2，如果内容图片大于等于3  多图  type 3
     * 3，如果内容没有图片，无图  type 0
     *
     * 第二个功能：保存封面图片与素材的关系
     * @param dto
     * @param wmNews
     * @param materials
     */
    private void saveRelativeInfoForCover(WmNewsDto dto, WmNews wmNews, List<String> materials) {
        List<String> images = dto.getImages();
        if (dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){
        //如果当前封面类型为自动，则设置封面类型的数据
        if (materials.size() >= WM_NEWS_MANY_IMAGE) {
            //多图
            //设置type为3,并取前三个图片的url
            wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
            images = materials.stream().limit(3).collect(Collectors.toList());
        } else if (materials.size() > 0) {
            //单图
            //设置type为1,并取前1个图片的url
            wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
            images = materials.stream().limit(1).collect(Collectors.toList());
        }else {
            //无图
            //设置type为0
            wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
        }
            //修改文章
        if (images != null && images.size() > 0) {
            //如果有图片加入wmNews对象中
            wmNews.setImages(StringUtils.join(images,","));
        }
        //调用方法修改
            this.updateById(wmNews);
        }
        if (images != null && images.size() > 0){
            //保存文章图片与素材的关系到数据库中
            saveRelativeInfo(materials,wmNews.getId(),WemediaConstants.WM_COVER_REFERENCE);
        }
    }



    /**
     * 处理文章内容图片与素材的关系
     *
     * @param materials
     * @param newsId
     */
    private void saveRelativeInfoForContent(List<String> materials, Integer newsId) {
        saveRelativeInfo(materials, newsId, WemediaConstants.WM_CONTENT_REFERENCE);
    }

    @Autowired
    private WmMaterialMapper wmMaterialMapper;
    /**
     * 保存文章图片与素材的关系到数据库中
     *
     * @param materials
     * @param newsId
     * @param type
     */
    private void saveRelativeInfo(List<String> materials, Integer newsId, Short type) {
        if (materials != null && !materials.isEmpty()) {
            //通过图片url查询素材id
            List<WmMaterial> dbMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, materials));
            //判断素材是否有效
            if (dbMaterials == null && dbMaterials.isEmpty()) {
                //手动抛出异常   第一个功能：能够提示调用者素材失效了，第二个功能，进行数据的回滚
                throw new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
            }
            if (dbMaterials.size() != materials.size()){
                throw new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
            }
            //获取全部素材id
            List<Integer> idCollect = dbMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());
            //批量保存
            wmNewsMaterialMapper.saveRelations(idCollect,newsId,type);
        }
    }


    /**
     * 提取文章内容中的图片信息
     *
     * @param content
     * @return
     */
    private List<String> ectractUrlInfo(String content) {
        List<String> list = new ArrayList<>();
        //解析内容JSON字符串为map
        List<Map> maps = JSON.parseArray(content, Map.class);
        for (Map map : maps) {
            if ("image".equals(map.get("type"))) {
                String imageUrl = (String) map.get("value");
                list.add(imageUrl);
            }
        }
        return list;
    }
}
